package com.hinotoyk.testsystem.config;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: testsystem
 * @description:
 * @author: DYJ
 * @create: 2019-11-14 09:45
 **/

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // setLoginUrl 如果不设置值，默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        shiroFilterFactoryBean.setLoginUrl("/login");

        // 设置无权限时跳转的 url;
        shiroFilterFactoryBean.setUnauthorizedUrl("/UsrLMT");

        // 设置拦截器,匹配原则是最上面的最优先匹配
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //用户，需要角色权限 “emp”
        //filterChainDefinitionMap.put("/emp/*Detail", "roles[emp]");

        //管理员，需要角色权限 “admin”
        //filterChainDefinitionMap.put("/admin/**", "roles[admin]");

        //开放登陆接口
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/register", "anon");

        //访问静态资源
        //filterChainDefinitionMap.put("/bootstrap/**","anon");
        //filterChainDefinitionMap.put("/bootstrap-fileinput/**","anon");
        //filterChainDefinitionMap.put("/ckplayer/**","anon");

        //其余接口一律拦截
        //主要这行代码必须放在所有权限设置的最后，不然会导致所有 url 都被拦截
        //filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        //System.out.println("Shiro拦截器工厂类注入成功");
        return shiroFilterFactoryBean;
    }



    /**
     * 注入 securityManager
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //设置realm
        securityManager.setAuthenticator(modularRealmAuthenticator());

        List<Realm> realms = new ArrayList<>();
        realms.add(getStudentRealm());
        realms.add(getTeacherRealm());
        realms.add(getAdminRealm());

        // 设置realm.
        securityManager.setRealms(realms);

        securityManager.setSessionManager(getDefaultWebSessionManager());
        return securityManager;

    }

    /**
     * 系统自带的Realm管理，主要针对多realm
     * */
    @Bean
    public ModularRealmAuthenticator modularRealmAuthenticator() {
        //自己重写的ModularRealmAuthenticator
        UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return modularRealmAuthenticator;
    }

    //配置sessionDAO
    @Bean(name="sessionDAO")
    public MemorySessionDAO getMemorySessionDAO(){
        MemorySessionDAO sessionDAO = new MemorySessionDAO();
        return sessionDAO;
    }

    //配置shiro session 的一个管理器
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 设置session过期时间
        sessionManager.setGlobalSessionTimeout(60*60*1000);
        // 请注意看代码
        sessionManager.setSessionDAO(getMemorySessionDAO());
        return sessionManager;
    }



    /**
     * 密码匹配凭证管理器
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 采用MD5方式加密
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        // 设置加密次数
        hashedCredentialsMatcher.setHashIterations(1024);
        return hashedCredentialsMatcher;
    }


    /**
     * 自定义身份认证 realm;
     * <p>
     * 必须写这个类，并加上 @Bean 注解，目的是注入 CustomRealm，
     * 否则会影响 CustomRealm类 中其他类的依赖注入,可以在这里加入自定义密码匹配器
     */
    @Bean(name="TeacherRealm")
    public TeacherRealm getTeacherRealm(){
        TeacherRealm teacherRealm = new TeacherRealm();
        teacherRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return teacherRealm;
    }

    @Bean(name="StudentRealm")
    public StudentRealm getStudentRealm(){
        StudentRealm studentRealm = new StudentRealm();
        studentRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return studentRealm;
    }

    @Bean(name="AdminRealm")
    public AdminRealm getAdminRealm(){
        AdminRealm adminRealm = new AdminRealm();
        adminRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return adminRealm;
    }
}
    